package com.sxhuayuan.parking.service.impl;

import com.sxhuayuan.parking.compenent.Filter;
import com.sxhuayuan.parking.compenent.Message;
import com.sxhuayuan.parking.compenent.Page;
import com.sxhuayuan.parking.compenent.Pageable;
import com.sxhuayuan.parking.compenent.shiro.AccountType;
import com.sxhuayuan.parking.compenent.shiro.Principal;
import com.sxhuayuan.parking.compenent.web.RespMessage.Status;
import com.sxhuayuan.parking.dao.*;
import com.sxhuayuan.parking.entity.*;
import com.sxhuayuan.parking.exception.MyException;
import com.sxhuayuan.parking.service.AgentService;
import com.sxhuayuan.parking.service.ParkingLotService;
import com.sxhuayuan.parking.service.RoleService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.util.*;

@Service("agentServiceImpl")
public class AgentServiceImpl extends BaseServiceImpl<Agent, Long> implements AgentService {

	@Autowired
	AgentDao dao;
	@Autowired
	AgentRelationDao agentRelationDao;
	@Autowired
	RoleService roleService;
	@Autowired
	ParkingLotService lotService;
	@Autowired
	ProfitStatisticsDao profitStatisticsDao;
	@Autowired
	MonthlyProfitDao monthlyProfitDao;

	@Override
	public BaseDao<Agent, Long> getDAO() {
		return dao;
	}

	@Override
	public Page<Agent> findPage(Pageable pageable, Agent agent) {
		StringBuilder sb = new StringBuilder();
		List<Filter> filters = pageable.getFilters();
		String salesmanName=null;
		if (filters != null) {
			for (Filter filter : filters) {
				if ("salesmanName".equals(filter.getProperty())){
					salesmanName = (String) filter.getValue();
				}
				setCondition(sb, filter);
			}
		}
		StringBuilder sb2 = new StringBuilder("select a from Agent a ");

		if (salesmanName!=null){
			sb2.append(" left join Salesman s on a.salesmanId=s.id ");
		}
		if (agent==null){
			sb2.append(" where 1=1 ");
		}else {
			sb2.append(" left join AgentRelation r on a.id=r.child.id  where r.parent.id=").append(agent.getId()).append(" and r.level <> 0");
		}
		sb.insert(0,sb2);
		sb.append(" order by a.id desc");
		return findPage(sb.toString(), sb.toString().replace("select a", "select count(a.id)"), pageable.getPageSize(), pageable.getPageNumber());
	}

	/** 组装查询条件 */
	private void setCondition(StringBuilder sb, Filter filter) {
		if (filter.getProperty() == null || "".equals(filter.getProperty()) || filter.getValue() == null || "".equals(filter.getValue())) {
			return;
		}
		switch (filter.getProperty()) {

		case "username": {
			sb.append(" and a.username='").append(filter.getValue()).append("' ");
			break;
		}

		case "name": {
			sb.append(" and a.name='").append(filter.getValue()).append("' ");
			break;
		}

		case "isEnabled": {
			sb.append(" and a.isEnabled=").append(filter.getValue());
			break;
		}

		case "isLocked": {
			sb.append(" and a.isLocked=").append(filter.getValue());
			break;
		}

		case "istartTime": {
			sb.append(" and a.createDate >='").append(filter.getValue()).append("' ");
			break;
		}

		case "iendTime": {
			sb.append(" and a.createDate <='").append(filter.getValue()).append("' ");
			break;
		}

		case "salesmanName": {
			sb.append(" and s.name ='").append(filter.getValue()).append("' ");
			break;
		}

		default:
		}

	}

	@Override
	@Transactional(readOnly = true)
	public boolean usernameExists(String username) {
		return dao.count((Root<Agent> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> criteriaBuilder.equal(root.get("username"), username)) > 0;
	}

	@Override
	@Transactional(readOnly = true)
	public Agent findByUsername(String username) {
		return dao.findByUsername(username);
	}

	@Override
	@Transactional(readOnly = true)
	public List<String> findAuthorities(Long id) {
		List<String> authorities = new ArrayList<>();
		Agent Agent = dao.findById(id).get();
		for (Role role : Agent.getRoles()) {
			authorities.addAll(role.getAuthorities());
		}
		return authorities;
	}

	@Override
	@Transactional(readOnly = true)
	public boolean isAuthenticated() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null && subject.getPrincipal() != null) {
			Principal principal = (Principal) subject.getPrincipal();
			if (principal.getType() == AccountType.agent) {
				return subject.isAuthenticated();
			}
		}
		return false;
	}

	@Override
	@Transactional(readOnly = true)
	public Agent getCurrent() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null && subject.getPrincipal() != null) {
			Principal principal = (Principal) subject.getPrincipal();
			if (principal.getType() == AccountType.agent) {
				return dao.findById(principal.getId()).get();
			}
		}
		return null;
	}

	@Override
	@Transactional(readOnly = true)
	public String getCurrentName() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null && subject.getPrincipal() != null) {
			Principal principal = (Principal) subject.getPrincipal();
			if (principal.getType() == AccountType.agent) {
				return principal.getUsername();
			}
		}
		return null;
	}

	@Transactional(readOnly = true)
	public String getCurrentUsername() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null && subject.getPrincipal() != null) {
			Principal principal = (Principal) subject.getPrincipal();
			if (principal.getType() == AccountType.agent) {
				return principal.getUsername();
			}
		}
		return null;
	}

	@Override
	@Transactional
	@CacheEvict(value = { "agentAuthorization", "commonData" }, allEntries = true)
	public void save(Agent agent) {
		super.save(agent);
	}

	@Override
	@Transactional
	@CacheEvict(value = { "agentAuthorization", "commonData" }, allEntries = true)
	public void save(Agent agent, Agent parent) {
		agent.setPassword(DigestUtils.md5Hex(agent.getPassword()));
		agent.setParent(parent);
		dao.save(agent);
		if (Objects.nonNull(parent)) {
			agent.setOemConfig(parent.getOemConfig());
			List<AgentRelation> parentList = agentRelationDao.findAllParents(parent);
			Set<AgentRelation> relations = new HashSet<>();
			// 先保存直接关系,自己跟自己的关系
			relations.add(new AgentRelation(agent, agent, 0));
			for (AgentRelation r : parentList) {
				// 代理添加的
				relations.add(new AgentRelation(r.getParent(), agent, r.getLevel() + 1));
			}
			agentRelationDao.saveAll(relations);
		} else {
			agentRelationDao.save(new AgentRelation(agent, agent, 0));
		}
	}

	@Override
	@Transactional
	@CacheEvict(value = { "agentAuthorization", "commonData" }, allEntries = true)
	public void delete(Long... ids) {
		super.delete(ids);
	}

	@Override
	@Transactional
	@CacheEvict(value = { "agentAuthorization", "commonData" }, allEntries = true)
	public void delete(Agent Agent) {
		super.delete(Agent);
	}

	/** 删除 */
	@Override
	@Transactional
	@CacheEvict(value = { "agentAuthorization", "commonData" }, allEntries = true)
	public void delete(Long id) {
		List<ParkingLot> carFieldS = new ArrayList<>();
		List<ParkingLot> list = lotService.findByAgent(id);
		if (Objects.nonNull(list) && list.size() > 0) {
			for (ParkingLot parkingLot : list) {
				parkingLot.setAgent(null);
				carFieldS.add(parkingLot);
			}
			lotService.saveList(carFieldS);
		}
		// 代理角色是代理单方面维护的，删除代理时，会自动删除，不用单独删除
		// dao.deletaAgentRole(id);
		/** 删除代理关系表 */
		agentRelationDao.deleteRelation(id);
		/** 代理都删除了 那么就也要删除代理添加的车场 */
		lotService.deleteByAgent(id);
		/** 删除代理的分润统计 */
		profitStatisticsDao.deleteByAgentId(id);
		/** 删除代理的月分润统计 */
		monthlyProfitDao.deleteByAgentId(id);
		/** 删除代理表 */
		dao.deleteById(id);
	}

	@Override
	@Transactional
	@CacheEvict(value = { "agentAuthorization", "commonData" }, allEntries = true)
	public Agent update(Agent agent) {
		if (Objects.isNull(agent.getId())) {
			throw new MyException(Status.VALID_ERR, Message.FORM_VALID_FAIL);
		}
		Agent agentSql = this.findOne(agent.getId());
		/** 用户名不能相同 */
		if (!agent.getUsername().equals(agentSql.getUsername())) {
			if (Objects.nonNull(this.findByUsername(agent.getUsername()))) {
				/** 用户名存在 */
				throw new MyException(Status.ERROR, Message.FORM_USERNAME_EXISTS);
			}
		}
		/** 判断密码是否发生了改变 */
		if (!StringUtils.isEmpty(agent.getPassword()) && !agent.getPassword().equals(agentSql.getPassword())) {
			agentSql.setPassword(DigestUtils.md5Hex(agent.getPassword()));
		}
		agentSql.setWeixinRate(agent.getWeixinRate());
		agentSql.setAlipayRate(agent.getAlipayRate());
		agentSql.setProfitProportion(agent.getProfitProportion());
		agentSql.setUsername(agent.getUsername());
		agentSql.setName(agent.getName());
		agentSql.setIsEnabled(agent.getIsEnabled());
		if(agentSql.getParent()==null){
			if (agent.getOemConfig()!=null){
				agentSql.setOemConfig(agent.getOemConfig());
			}
			if (agent.getSalesmanId()!=null){
				agentSql.setSalesmanId(agent.getSalesmanId());
			}
		}
		/*
		 * Role role = roleService.findOne(Agent.getRoles()); Set<Role> roles = new
		 * HashSet<>(); roles.add(role); agentSql.setRoles(roles);
		 */
		return dao.save(agentSql);
	}

	@Override
	public boolean isPermission(Agent parent, Agent child) {
		Long count = agentRelationDao.findRelation(parent, child);
		return count != null && count > 0;
	}

	@Override
	public boolean isPermission(Agent child) {
		Agent current = getCurrent();
		if (current.getId().equals(child.getId())) {
			return true;
		}
		return isPermission(getCurrent(), child);
	}

	@Override
	public List<Agent> getChildrenList(Agent parent) {
		return agentRelationDao.findAllChildren(parent);
	}

	@Override
	public Long countAll(Agent agent) {
		if (agent != null) {
			return dao.countByAgent(agent);
		}
		return dao.count();
	}

	@Override
	public List<Agent> findBySalesman(Salesman salesman) {
		Assert.notNull(salesman, "不能为空");
		return dao.findBySalesmanId(salesman.getId());
	}

	@Override
	public Page<Agent> findPage(Pageable pageable, Salesman salesman) {
		StringBuilder sb = new StringBuilder("select a from Agent a where a.salesmanId=").append(salesman.getId());
		List<Filter> filters = pageable.getFilters();
		if (filters != null) {
			for (Filter filter : filters) {
				setCondition(sb, filter);
			}
		}
		sb.append(" order by a.id desc");
		return findPage(sb.toString(), sb.toString().replace("select a", "select count(a.id)"), pageable.getPageSize(), pageable.getPageNumber());
	}
}
